home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The X-Philes (2nd Revision)
/
The X-Philes Number 1 (1995).iso
/
xphiles
/
hp48_2
/
areuh.tar
/
areuh
/
linker
/
exp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-10-10
|
16KB
|
635 lines
/*
* Authors :
* Pierre DAVID (pda@masi.ibp.fr or pda@frunip62.bitnet)
* Janick TAILLANDIER
*
* This program can be freely used or distributed as long as this
* note is kept.
*
* This program is provided "as is".
*/
/******************************************************************************
TITAN ASSEMBLER
EXPRESSION EVALUATION
calc_expression, reduce_E, reduce_T, reduce_F, reduce_B, reduce_X,
reduce_P, dec_value, hex_value, bin_value, ascii_value, label_value, apply,
trunc, next_char, append_extexp
******************************************************************************/
#include "flag.h"
#if ASSEMBLER
#include "aglobal.h"
#else
#include "lglobal.h"
#endif
uchar extexp [4*MAXLEN] ;
uchar *pexp, *pextexp ;
uchar *xlabel ;
int relabs ;
extern saddr symbol_value() ;
saddr reduce_E(), reduce_T(), reduce_F(), reduce_B(), reduce_X(), reduce_P(),
dec_value(), hex_value(), bin_value(), ascii_value(), label_value(),
apply(), trunc() ;
void next_char(), append_extexp() ;
/******************************************************************************
CALC_EXPRESSION
synopsis : saddr calc_expression (exp)
uchar *exp
description : That's the expression evaluator. Productions used are :
E -> T { {+|-} T }*
T -> F { {*|/} F }*
F -> B { {&|!} B }*
B -> X | -X | `X (two's and one's complement)
X -> N { {~|^} N }*
P -> D | #<hex> | %<bin> | '<ascii>' | \<ascii>\ | <label> | * | (E)
D -> <dec> if expression evaluated by ASSSEMBLER
D -> <dec> | <dec> r if expression evaluated by LINKER
where E : expression
T : term
F : factor
B : boolean
X : exponentiation
P : primary
D : decimal number
warning : with this grammar, 5--5 is valid (5 minus -5), but 5---5 is not.
This can be modified by : B -> -B | P . The code is more complex,
and I'm not sure that it's a real improvement.
note : Algorithm used is recursive descent (Mr Vermeulen would be horrified !)
like Forth/Assembler rom based assembler, but is quietly different...
******************************************************************************/
saddr calc_expression (exp)
uchar *exp;
{
saddr val;
pextexp = extexp ;
pexp = exp ;
val = reduce_E() ;
if (((val>=0L)||(val==EXP_EXT))&&(*pexp!=EOL)&&(*pexp!=' ')&&(*pexp!='\t'))
{
error(WRNEXP, "") ; /* illegal expression */
val = EXP_ERR ;
}
*pextexp = EOL ;
return (val) ;
}
/******************************************************************************
REDUCE_E
synopsis : saddr reduce_E()
description : This function reduces a given expression starting at pexp.
******************************************************************************/
saddr reduce_E()
{
saddr val1, val2;
uchar op, lrelabs;
val1 = reduce_T () ;
while ((((op = *pexp)=='+')||(op=='-'))&&(val1!=EXP_ERR))
{
lrelabs = relabs ;
next_char () ;
val2 = reduce_T () ;
val1 = apply (val1, op, val2, lrelabs, relabs) ;
}
return (val1) ;
}
/******************************************************************************
REDUCE_T
synopsis : saddr reduce_T ()
description : same as above, for T-production
******************************************************************************/
saddr reduce_T ()
{
saddr val1, val2 ;
uchar op, lrelabs ;
val1 = reduce_F () ;
while ((((op = *pexp)=='*')||(op=='/'))&&(val1!=EXP_ERR))
{
lrelabs = relabs ;
next_char () ;
val2 = reduce_F () ;
val1 = apply (val1, op, val2, lrelabs, relabs) ;
}
return (val1) ;
}
/******************************************************************************
REDUCE_F
synopsis : saddr reduce_F ()
description : same as reduce_E
******************************************************************************/
saddr reduce_F ()
{
saddr val1, val2;
uchar op, lrelabs ;
val1 = reduce_B () ;
while ((((op = *pexp)=='&')||(op=='!'))&&(val1!=EXP_ERR))
{
lrelabs = relabs ;
next_char () ;
val2 = reduce_B () ;
val1 = apply (val1, op, val2, lrelabs, relabs) ;
}
return (val1) ;
}
/******************************************************************************
REDUCE_B
synopsis : saddr reduce_B ()
description : reduces a boolean factor. This must be done by reduction of minus
sign eventually.
******************************************************************************/
saddr reduce_B ()
{
saddr val;
uchar op ;
op = *pexp ;
if ((op=='-')||(op=='\`')) next_char () ;
val = reduce_X () ;
if (val<0L)
return(val) ;
switch (op)
{
case '-' :
return (trunc (-val)) ;
case '\`' :
return (trunc (~val)) ;
default :
return (val) ;
}
}
/******************************************************************************
REDUCE_X
synopsis : saddr reduce_X ()
description : same as reduce_E
******************************************************************************/
saddr reduce_X ()
{
saddr val1, val2;
uchar op, lrelabs;
val1 = reduce_P () ;
while ((((op = *pexp)=='~')||(op=='^'))&&(val1!=EXP_ERR))
{
lrelabs = relabs ;
next_char () ;
val2 = reduce_P () ;
val1 = apply (val1, op, val2, lrelabs, relabs) ;
}
return (val1) ;
}
/******************************************************************************
REDUCE_P
synopsis : saddr reduce_P ()
description : these are the terminal rules.
note : rule P -> D is implemented "in line" in this code (not as a separate
function).
******************************************************************************/
saddr reduce_P ()
{
saddr val ;
uchar limit, line[MAXLEN] ;
switch (*pexp)
{
case '#' :
next_char () ;
if (((*pexp>='0')&&(*pexp<='9')) ||
((*pexp>='A')&&(*pexp<='F')) ||
((*pexp>='a')&&(*pexp<='f')))
val = hex_value () ;
else
{
error (WRNIHX,""); /* illegal hexadecimal constant */
val = EXP_ERR ;
}
relabs = LABS ;
break ;
case '%' :
next_char () ;
if ((*pexp=='0')||(*pexp=='1'))
val = bin_value () ;
else
{
error (WRNIBC, "") ; /* illegal binary constant */
val = EXP_ERR ;
}
relabs = LABS ;
break ;
case '\'' :
case '\\' :
limit = *pexp ;
next_char () ;
val = ascii_value (limit) ;
if (*pexp!=limit)
{
error (WRNASC,""); /* illegal ascii constant */
val = EXP_ERR ;
}
next_char () ;
relabs = LABS ;
break ;
case '*' :
val = pc ;
pexp++ ;
sprintf (line, "%ldr", pc) ;
relabs = LREL ;
append_extexp (line) ;
break ;
case '(' :
next_char () ;
val = reduce_E () ;
if ((*pexp!=')')&&(val>=0))
{
error (WRNPAR, "") ; /* mismatched parenthesis */
val = EXP_ERR ;
}
next_char () ;
break ;
case EOL :
error (WRNEXP,"") ; /* illegal expression */
val = EXP_ERR ;
break ;
default :
if ((*pexp>='0')&&(*pexp<='9'))
{
val = dec_value () ;
relabs = LABS ;
#if LINKER
if (*pexp=='r')
{
next_char() ;
relabs = LREL ;
val += tmodule[file].m_ad ;
}
#endif
}
else val = label_value () ;
break ;
}
return (val) ;
}
/******************************************************************************
DEC_VALUE
synopsis : saddr dec_value ()
descrption : This function returns the decimal value of a constant. The search
is stopped when a non numeric digit is reached.
(this can be ),+,-,*,/,&,!).
Finally, the founded value is returned.
note : this function doesn't check overflow. If there is, numbers are treated
as 20 bits words, and overflow doesn't propagate on 32 bits of an
integer (-1 is never reached when calculus).
******************************************************************************/
saddr dec_value ()
{
saddr val=0L ;
do
{
val = trunc (val * 10L + (saddr) (*pexp-'0') ) ;
next_char () ;
}
while ((*pexp>='0')&&(*pexp<='9')) ;
return (val);
}
/******************************************************************************
HEX_VALUE
synopsis : saddr hex_value ()
description : same as above for hexadecimal constants
******************************************************************************/
saddr hex_value ()
{
saddr i, val = 0L ;
while ( ((*pexp>='0')&&(*pexp<='9')) ||
((*pexp>='A')&&(*pexp<='F')) ||
((*pexp>='a')&&(*pexp<='f')) )
{
if (*pexp<='9') i = (long int) ((*pexp) - '0') ;
else if (*pexp<='F') i = (long int) ((*pexp) - 'A' + 10) ;
else i = (long int) ((*pexp) - 'a' + 10) ;
val = trunc (val*16L + i) ;
next_char () ;
}
return (val) ;
}
/******************************************************************************
BIN_VALUE
synopsis : saddr bin_value ()
description : same as above for binary constants
******************************************************************************/
saddr bin_value ()
{
saddr val = 0L ;
while ((*pexp=='0')||(*pexp=='1'))
{
val = trunc (val*2L + ((saddr) ((*pexp) - '0'))) ;
next_char () ;
}
return (val) ;
}
/******************************************************************************
ASCII_VALUE
synopsis : saddr ascii_value ()
description : same as above, but the search is stopped when encoutered a '.
The pointer *pexp stands on this character.
******************************************************************************/
saddr ascii_value (limit)
uchar limit ;
{
saddr val = 0 ;
while ((*pexp!=EOL)&&(*pexp!=limit))
{
val = trunc (val*256L + ((saddr) *pexp)) ;
next_char () ;
}
return (val) ;
}
/******************************************************************************
LABEL_VALUE
synopsis : saddr label_value ()
description : parses the symbol, then tries to return the value founded in the
symbol list.
******************************************************************************/
saddr label_value ()
{
uchar label[LBLLEN+2], *plabel ;
int mx, need_par = 0, j = 0 ;
saddr val ;
mx = LBLLEN + ((*pexp=='=') ? 1 : 0) ;
while ((*pexp!=EOL)&&(*pexp!=' ')&&(*pexp!='\t')&&
(*pexp!=')')&&(*pexp!='\\'))
{
if (j<mx) label[j++] = *pexp ;
pexp++ ;
}
label[j] = EOL ;
plabel = label ;
if ((val = symbol_value (label)) >= (saddr) 0)
{ /* found, copy value */
if (relabs==LREL) sprintf (label, "%ldr", val) ;
else sprintf (label, "%ld", val) ;
}
else if ((val == LBL_UDF) || (val == LBL_IVL))
{ /* UDF : label not (yet) declared, IVl : invalid label */
*plabel = EOL ; /* incoherent value */
val = EXP_ERR ;
}
else if ((val == LBL_EXT) || (val == LBL_XEQ))
{ /* LBL_EXT: ext. label not known, LBL_XEQ: global defined with ext. */
val = EXP_EXT ; /* keep label name */
}
else /* (val == LBL_SEQ) */
{ /* LBL_SEQ : synonym, expandable */
plabel = xlabel ; /* get definition of label */
need_par = 1 ; /* enclose label with (...) */
val = EXP_EXT ; /* and store it into extep */
}
if (need_par) append_extexp ("(") ;
append_extexp (plabel) ;
if (need_par) append_extexp (")") ;
return (val) ;
}
/******************************************************************************
APPLY
synopsis : saddr apply (val1, op, val2, relabs1, relabs2)
saddr val1, val2
uchar op, relabs1, relabs2
description : calculate the value of binary operator op applied to operands
val1 & val2.
note : under overflow condition, numbers are truncated to 20 bits.
******************************************************************************/
saddr apply (val1, op, val2, relabs1, relabs2)
uchar op, relabs1, relabs2 ;
saddr val1, val2 ;
{
saddr val ;
if (val2==EXP_ERR) return (EXP_ERR) ;
if ((val1==EXP_EXT)||(val2==EXP_EXT)) return (EXP_EXT) ;
switch (op)
{
case '+' :
val = trunc (val1 + val2) ;
break ;
case '-' :
val = trunc (val1 - val2 ) ;
break ;
case '*' :
val = trunc (val1 * val2 ) ;
break ;
case '/' :
#if ASSEMBLER
val = (val2 ? val1 / val2 : EXP_ERR ) ;
#else
val = (val2 ? val1 / val2 : EXP_EXT ) ;
#endif
if (val2==0L) error (WRNNUL, "") ; /* null divisor */
break ;
case '&' :
val = val1 & val2 ;
break ;
case '!' :
val = val1 | val2 ;
break ;
case '~' :
val = trunc (val1*256 + val2) ;
break ;
case '^' :
if ((val1<0)||(val2<0)||((val1==0)&&(val2==0)))
{
error (WRNIXP, "") ; /* Illegal exponentiation */
#if ASSEMLER
val = EXP_ERR ;
#else
val = EXP_EXT ;
#endif
}
else
{
val = 1 ;
for (;val2>0 ; val2--) val *= val1 ;
val = trunc (val) ;
}
break ;
}
if ((relabs1==LUDF)||(relabs2==LUDF)) relabs = LUDF ;
else if ((relabs1==LREL)||(relabs2==LREL)) relabs = LREL ;
else relabs = LABS ;
return (val) ;
}
/******************************************************************************
TRUNC
synopsis : saddr trunc (val)
saddr val
description : truncates 32 bits integer to 24 bits.
******************************************************************************/
saddr trunc (val)
saddr val ;
{
return (val & 0xffffff) ;
}
/******************************************************************************
NEXT_CHAR
synopsis : void next_char ()
description : stores the current character in extexp variable, and moves the
expression pointer (pexp) forward one position.
******************************************************************************/
void next_char ()
{
*pextexp = *pexp ;
pextexp++ ;
pexp++ ;
}
/******************************************************************************
APPEND_EXTEXP
synopsis : void append_extexp (line)
uchar *line ;
description : append line to extexp string.
******************************************************************************/
void append_extexp (line)
uchar *line ;
{
while (*line)
{
*pextexp = *line ;
pextexp++ ;
line++ ;
}
}